home *** CD-ROM | disk | FTP | other *** search
- #define _KERNEL
- #include "ixemul.h"
-
- #include <exec/memory.h>
- #include <signal.h>
- #include <unistd.h>
-
- /*
- * Glue asm to C.
- */
- asm("
- .globl ___stkext
- ___stkext:
- moveml d0/d1/a0/a1/a6,sp@-
- subqw #4,sp | sigset_t
- jbsr _atomic_on
- subw #12,sp | struct StackSwapStruct
- jbsr _stkext
- movel 4:W,a6
- movel sp,a0
- jsr a6@(-0x2dc) | StackSwap(a0)
- jbsr _atomic_off
- addqw #4,sp | StackSwapStruct is not copied
- moveml sp@+,d0/d1/a0/a1/a6
- rts
-
- .globl ___stkext_f | see above
- ___stkext_f:
- moveml d0/d1/a0/a1/a6,sp@-
- subqw #4,sp
- jbsr _atomic_on
- subw #12,sp
- jbsr _stkext_f
- movel 4:W,a6
- movel sp,a0
- jsr a6@(-0x2dc)
- jbsr _atomic_off
- addqw #4,sp
- moveml sp@+,d0/d1/a0/a1/a6
- rts
-
- .globl ___stkrst_f | see above
- ___stkrst_f:
- moveml d0/d1/a0/a1/a6,sp@-
- subqw #4,sp
- jbsr _atomic_on
- subw #12,sp
- jbsr _stkrst_f
- movel 4:W,a6
- movel sp,a0
- jsr a6@(-0x2dc)
- jbsr _atomic_off
- addqw #4,sp
- moveml sp@+,d0/d1/a0/a1/a6
- rts
-
- .globl ___stkrst
- ___stkrst:
- moveml d0/d1/a0/a1/a6,sp@- | preserve registers
- subqw #4,sp | make room for the signal mask
- jbsr _atomic_on | disable all signals
- subw #12,sp | make room for a StackSwapStruct
- jbsr _stkrst | calculate either target sp or StackSwapStruct
- tstl d0 | set target sp?
- jeq swpfrm | jump if not
- movel d0,a0 | I have a lot of preserved registers and
- | returnadresses on the stack. It's necessary
- | to copy them to the new location
- moveq #6,d0 | 1 rts, 5 regs and 1 signal mask to copy (2+5+1)-1=7
- lea sp@(40:W),a1 | get address of uppermost byte+1 (1+5+1)*4+12=40
- cmpl a0,a1 | compare with target location
- jls lp1 | jump if source<=target
- lea a0@(-28:W),a0 | else start at lower bound (1+5+1)*4=28
- lea a1@(-28:W),a1
- movel a0,sp | set sp to reserve the room
- lp0: movel a1@+,a0@+ | copy with raising addresses
- dbra d0,lp0 | as long as d0>=0.
- jra endlp | ready
- lp1: movel a1@-,a0@- | copy with falling addresses
- dbra d0,lp1 | as long as d0>=0
- movel a0,sp | finally set sp
- jra endlp | ready
- swpfrm: movel 4:W,a6 | If sp wasn't set call StackSwap()
- movel sp,a0
- jsr a6@(-0x2dc)
- endlp: jbsr _atomic_off | reenable signals
- addqw #4,sp | adjust sp
- moveml sp@+,d0/d1/a0/a1/a6 | restore registers
- rts | and return
- ");
-
- void __stkrst_f(void);
-
- #define STK_UPPER \
- (u.u_stk_used != NULL ? u.u_stk_used->upper : u.u_org_upper)
-
- #define STK_LOWER \
- (u.u_stk_used != NULL ? (void *)(u.u_stk_used + 1) : u.u_org_lower)
-
- #define stk_safezone 6144 /* into ixprefs? */
- #define stk_minframe 32768
-
- void initstack(void)
- {
- struct Process *me;
- APTR lower, upper;
-
- me = (struct Process *)SysBase->ThisTask;
-
- u.u_tc_splower = me->pr_Task.tc_SPLower;
- u.u_tc_spupper = me->pr_Task.tc_SPUpper;
-
- if (me->pr_CLI)
- {
- /* Process stackframe:
- * me->pr_ReturnAddr points to size of stack (ULONG)
- * +4 returnaddress
- * +8 stackframe
- */
- lower = (char *)me->pr_ReturnAddr + 8 - *(ULONG *)me->pr_ReturnAddr;
- upper = (char *)me->pr_ReturnAddr + 8;
- }
- else
- {
- lower = u.u_tc_splower;
- upper = u.u_tc_spupper;
- }
-
- u.u_org_lower = lower; /* Lower stack bound */
- u.u_org_upper = upper; /* Upper stack bound +1 */
- u.u_stk_used = NULL; /* Stackframes in use */
- u.u_stk_spare = NULL; /* Spare stackframes */
- u.u_stk_current=u.u_stk_max=0; /* No extended stackframes at this point */
-
- u.u_stk_limit = (void **)-1; /* Used uninitialized? Raise address error */
- u.u_stk_argbt = 256; /* set some useful default */
- }
-
- void __init_stk_limit(void **limit, unsigned long argbytes)
- {
- u.u_stk_limit = limit;
- u.u_stk_argbt = argbytes;
- *limit = (char *)u.u_org_lower + stk_safezone + argbytes;
- }
-
- /*
- * Free all spare stackframes
- */
- void freestack(void)
- {
- struct stackframe *sf, *s2;
-
- sf = u.u_stk_spare;
- u.u_stk_spare = NULL;
- while (sf != NULL)
- {
- s2 = sf->next;
- FreeMem(sf, (char *)sf->upper - (char *)sf);
- sf = s2;
- }
- }
-
- void __stkovf(void)
- {
- u.u_stk_limit = NULL; /* disable stackextend from now on */
- for (;;)
- kill(getpid(), SIGSEGV); /* Ciao */
- }
-
- /*
- * Signal routines may want to benefit from stackextension too -
- * so make all the stack handling functions atomic.
- * FIXME: This seems to have the potential to break a Forbid() ?!?
- */
- void atomic_on(sigset_t old)
- {
- sigset_t fill;
- sigfillset(&fill);
- sigprocmask(SIG_SETMASK, &fill, &old);
- }
-
- void atomic_off(sigset_t old)
- {
- sigprocmask(SIG_SETMASK, &old, NULL);
- }
-
- /*
- * Move a stackframe with a minimum of requiredstack bytes to the used list
- * and fill the StackSwapStruct structure.
- */
- static void pushframe(ULONG requiredstack, struct StackSwapStruct *sss, sigset_t *old)
- {
- struct stackframe *sf;
- ULONG recommendedstack;
-
- requiredstack += stk_safezone + u.u_stk_argbt;
- if (requiredstack < stk_minframe)
- requiredstack = stk_minframe;
-
- recommendedstack=u.u_stk_max-u.u_stk_current;
- if (recommendedstack<requiredstack)
- recommendedstack=requiredstack;
-
- for (;;)
- {
- sf = u.u_stk_spare; /* get a stackframe from the spares list */
- if (sf == NULL)
- { /* stack overflown */
- for (; recommendedstack>=requiredstack; recommendedstack/=2)
- {
- sf = AllocMem(recommendedstack + sizeof(struct stackframe), MEMF_PUBLIC);
- if (sf != NULL)
- break;
- }
- if (sf == NULL)
- { /* and we have no way to extend it :-| */
- sigprocmask(SIG_SETMASK, old, NULL);
- __stkovf();
- }
- sf->upper = (char *)(sf + 1) + recommendedstack;
- break;
- }
- u.u_stk_spare = sf->next;
- if ((char *)sf->upper - (char *)(sf + 1) >= recommendedstack)
- break;
- FreeMem(sf, (char *)sf->upper - (char *)sf);
- }
-
- /* Add stackframe to the used list */
- sf->next = u.u_stk_used;
- u.u_stk_used = sf;
- *u.u_stk_limit = (char *)(sf + 1) + stk_safezone + u.u_stk_argbt;
-
- /* prepare StackSwapStruct */
- sss->stk_Pointer = sf->upper;
- sss->stk_Lower = sf + 1;
- sss->stk_Upper = (ULONG)sf->upper;
-
- /* Update stack statistics. */
- u.u_stk_current += (char *)sf->upper - (char *)(sf + 1);
- if (u.u_stk_current > u.u_stk_max)
- u.u_stk_max = u.u_stk_current;
- }
-
- /*
- * Allocate a new stackframe with d0 bytes minimum.
- */
- void stkext(struct StackSwapStruct sss, sigset_t old,
- long d0, long d1, long a0, long a1, long a6, long ret1)
- {
- void *callsp = &ret1 + 1;
- int cpsize = (char *)callsp - (char *)&old;
-
- if (callsp >= STK_UPPER || callsp < STK_LOWER)
- return; /* User intentionally left area of stackextension */
-
- pushframe(d0, &sss, &old);
- *(char **)&sss.stk_Pointer -= cpsize;
- CopyMem(&old, sss.stk_Pointer, cpsize);
- }
-
- /*
- * Allocate a new stackframe with d0 bytes minimum, copy the callers arguments
- * and set his returnaddress (offset d1 from the sp when called) to stk_rst_f
- */
- void stkext_f(struct StackSwapStruct sss, sigset_t old,
- long d0, long d1, long a0, long a1, long a6, long ret1)
- {
- void *argtop, *callsp = &ret1 + 1;
- int cpsize;
-
- if (callsp >= STK_UPPER || callsp < STK_LOWER)
- return; /* User intentionally left area of stackextension */
-
- argtop = (char *)callsp + u.u_stk_argbt; /* Top of area with arguments */
- if (argtop > STK_UPPER)
- argtop = STK_UPPER;
- cpsize = (char *)argtop - (char *)&old;
-
- pushframe(d0 + u.u_stk_argbt, &sss, &old);
- *(char **)&sss.stk_Pointer -= cpsize;
- CopyMem(&old,sss.stk_Pointer, cpsize);
- u.u_stk_used->savesp = (char *)callsp + d1; /* store sp */
- *(void **)((char *)sss.stk_Upper - ((char *)argtop - (char *)callsp) + d1)
- = &__stkrst_f; /* set returnaddress */
- }
-
- /*
- * Move all used stackframes upto (and including) sf to the spares list
- * and fill the StackSwapStruct structure.
- */
- static void popframes(struct stackframe *sf, struct StackSwapStruct *sss)
- {
- struct stackframe *sf2;
-
- if (sf->next != NULL)
- {
- sss->stk_Lower = sf->next + 1;
- sss->stk_Upper = (ULONG)sf->next->upper;
- *u.u_stk_limit = (char *)(sf->next + 1) + stk_safezone + u.u_stk_argbt;
- }
- else
- {
- sss->stk_Lower = u.u_tc_splower;
- sss->stk_Upper = (ULONG)u.u_tc_spupper;
- *u.u_stk_limit = (char *)u.u_org_lower + stk_safezone + u.u_stk_argbt;
- }
- sf2 = u.u_stk_spare;
- u.u_stk_spare = u.u_stk_used;
- u.u_stk_used = sf->next;
- sf->next = sf2;
-
- /* Update stack statistics. */
- for (sf2 = u.u_stk_spare; sf2 != sf->next; sf2 = sf2->next)
- u.u_stk_current -= (char *)sf2->upper - (char *)(sf2 + 1);
- }
-
- /*
- * Set stackpointer back to some previous value
- * != NULL: on the same stackframe (returns sp)
- * == NULL: on another stackframe
- */
- void *stkrst(struct StackSwapStruct sss, sigset_t old,
- void *d0, long d1, long a0, long a1, long a6, long ret1)
- {
- void *callsp = &ret1 + 1;
- int cpsize = (char *)callsp - (char *)&old;
- struct stackframe *sf1, *sf2;
-
- if (d0 >= STK_LOWER && d0 < STK_UPPER)
- return d0;
-
- sf1 = u.u_stk_used;
- if (sf1 == NULL)
- return d0;
- for (;;)
- {
- sf2 = sf1->next;
- if (sf2 == NULL)
- {
- if (d0 < u.u_org_lower || d0 >= u.u_org_upper)
- return d0;
- break;
- }
- if (d0 >= (void *)(sf2 + 1) && d0 < sf2->upper) /* This stackframe fits */
- break;
- sf1 = sf2;
- }
- popframes(sf1, &sss);
- sss.stk_Pointer = (char *)d0 - cpsize;
- CopyMem(&old, sss.stk_Pointer,cpsize);
- return NULL;
- }
-
- /*
- * return to last stackframe
- */
- void stkrst_f(struct StackSwapStruct sss, sigset_t old,
- long d0, long d1, long a0, long a1, long a6)
- {
- void *callsp = &a6 + 1; /* This one has no returnaddress - it's a fallback for rts */
- int cpsize = (char *)callsp - (char *)&old;
-
- sss.stk_Pointer = (char *)u.u_stk_used->savesp - cpsize;
- popframes(u.u_stk_used, &sss);
- CopyMem(&old, sss.stk_Pointer, cpsize);
- }
-